package com.gsbelarus.gedemin.salary.util;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;

import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.client.util.DateTime;
import com.google.api.client.util.ExponentialBackOff;
import com.google.api.services.calendar.CalendarScopes;
import com.google.api.services.calendar.model.Event;
import com.google.api.services.calendar.model.Events;
import com.gsbelarus.gedemin.salary.R;
import com.gsbelarus.gedemin.salary.database.RealmHelper;
import com.gsbelarus.gedemin.salary.entity.model.DayEventModel;
import com.gsbelarus.gedemin.salary.entity.model.WorkScheduleModel;

import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import io.realm.RealmResults;

public class HolidaysHelper {

    private static final String PREF_ACCOUNT_NAME = "accountName";
    private static final String[] SCOPES = {CalendarScopes.CALENDAR_READONLY};

    private Context context;

    public HolidaysHelper(Context context) {
        this.context = context;
    }

    public void bindPublicHolidaysToBackend(RealmHelper realmHelper) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_YEAR, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.clear(Calendar.MINUTE);
        cal.clear(Calendar.SECOND);
        cal.clear(Calendar.MILLISECOND);
        DateTime startDateTime = new DateTime(cal.getTimeInMillis());

        WorkScheduleModel workScheduleModel = realmHelper.getWorkScheduleByDay(new Date(startDateTime.getValue()));
        boolean isContainsPublicHolidays = false;
        if (workScheduleModel != null && !workScheduleModel.getEvents().isEmpty()) {
            for (DayEventModel day : workScheduleModel.getEvents())
                if (day.getEventType() == DayEventModel.EventType.PUBLIC_HOLIDAY) {
                    isContainsPublicHolidays = true;
                    break;
                }
        }
        if (isContainsPublicHolidays) return;

        try {
            GoogleAccountCredential credential = auth();

            cal.add(Calendar.YEAR, 2);
            DateTime endDateTime = new DateTime(cal.getTimeInMillis());

            Events events = new com.google.api.services.calendar.Calendar.Builder(
                    AndroidHttp.newCompatibleTransport(), GsonFactory.getDefaultInstance(), credential)
                    .setApplicationName(context.getString(R.string.app_name))
                    .build().events().list("ru.by#holiday@group.v.calendar.google.com")
                    .setTimeMin(startDateTime)
                    .setTimeMax(endDateTime)
                    .setOrderBy("startTime")
                    .setSingleEvents(true)
                    .execute();

            List<Event> items = events.getItems();
            for (Event event : items) {
                DateTime start = event.getStart().getDate();

                DayEventModel dayEvent;
                if (event.getSummary().contains("Special Working Day"))
                    dayEvent = ModelFactory.newInstanceDayEventModel(realmHelper.getRealm().createObject(DayEventModel.class),
                            DayEventModel.EventType.CHANGE_WORK_SCHEDULE, event.getSummary(), true);
                else
                    dayEvent = ModelFactory.newInstanceDayEventModel(realmHelper.getRealm().createObject(DayEventModel.class),
                            DayEventModel.EventType.PUBLIC_HOLIDAY, event.getSummary(), true);
                WorkScheduleModel workSchedule = realmHelper.getWorkScheduleByDay(new Date(start.getValue()));
                if (workSchedule == null)
                    workSchedule = ModelFactory.newInstanseWorkScheduleModel(realmHelper.getRealm().createObject(WorkScheduleModel.class),
                            WorkScheduleModel.DayType.DAY_OFF, realmHelper.getLastEmployee(), new Date(start.getValue()));
                workSchedule.getEvents().add(dayEvent);
            }
        } catch (Exception e) {
            //Crashlytics.getInstance().core.logException(e);
            Log.d(HolidaysHelper.class.getSimpleName(), e.toString());
        }
    }

    public void bindMissedWeekendsToBackend(RealmHelper realmHelper) {
        RealmResults<WorkScheduleModel> results = realmHelper.getRealm().where(WorkScheduleModel.class).findAllSorted("date");
        Calendar nextCal = Calendar.getInstance();
        Calendar curCal = Calendar.getInstance();
        Calendar lastWorkCal = Calendar.getInstance();
        Calendar firstWorkCal = Calendar.getInstance();
        firstWorkCal.setTime(results.where().equalTo("dayTypeIndex", WorkScheduleModel.DayType.WORK.ordinal()).minimumDate("date"));
        lastWorkCal.setTime(results.where().equalTo("dayTypeIndex", WorkScheduleModel.DayType.WORK.ordinal()).maximumDate("date"));

        for (int i = 0; i < results.size() - 1; i++) {
            curCal.setTime(results.get(i).getDate());
            nextCal.setTime(results.get(i + 1).getDate());

            if (curCal.compareTo(firstWorkCal) < 0) continue;
            if (nextCal.compareTo(lastWorkCal) > 0) break;

            curCal.add(Calendar.DAY_OF_MONTH, 1);
            if (curCal.get(Calendar.YEAR) != nextCal.get(Calendar.YEAR) ||
                    curCal.get(Calendar.DAY_OF_YEAR) != nextCal.get(Calendar.DAY_OF_YEAR)) {

                ModelFactory.newInstanseWorkScheduleModel(realmHelper.getRealm().createObject(WorkScheduleModel.class),
                        WorkScheduleModel.DayType.DAY_OFF, realmHelper.getLastEmployee(), curCal.getTime());
            }
        }
    }

    public GoogleAccountCredential auth() {
        GoogleAccountCredential credential;
        SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
        if (settings.contains(PREF_ACCOUNT_NAME)) {
            credential = GoogleAccountCredential.usingOAuth2(
                    context, Arrays.asList(SCOPES))
                    .setBackOff(new ExponentialBackOff())
                    .setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null));
        } else {
            AccountManager accountManager = AccountManager.get(context);
            Account account = getAccount(accountManager);
            String accountName = account.name;
            SharedPreferences.Editor editor = settings.edit();
            editor.putString(PREF_ACCOUNT_NAME, accountName);
            editor.apply();

            credential = GoogleAccountCredential.usingOAuth2(
                    context, Arrays.asList(SCOPES))
                    .setBackOff(new ExponentialBackOff())
                    .setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null));
        }
        return credential;
    }

    private Account getAccount(AccountManager accountManager) {
        Account[] accounts = accountManager.getAccountsByType("com.google");
        Account account;
        if (accounts.length > 0) {
            account = accounts[0];
        } else {
            account = null;
        }
        return account;
    }
}
